package  net.dgg.dggcloud.service.jrcrm.utils;

import net.dgg.dggcloud.core.util.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 导出Excel表
 * 
 * @author 周潮
 * 
 * @param <T>应用泛型，代表任意一个符合javabean风格的类
 */
public class ExportExcel<T> {
	/**
	 * 导出excel
	 * 
	 * @param footTitle
	 *            脚标题
	 * @param dataset
	 *            控制数据
	 * @param out
	 *            输出流
	 * @param session
	 *            会话
	 */
	public void exportExcel(String footTitle, Collection<T> dataset,
			OutputStream out, HttpSession session) {
		export(footTitle, null, dataset, out, "yyyy-MM-dd", session);
	}

	/**
	 * 导出excel
	 * 
	 * @param footTitle
	 *            脚标题
	 * @param headers
	 *            表头
	 * @param dataset
	 *            控制数据
	 * @param out
	 *            输出流
	 * @param session
	 *            会话
	 */
	public void exportExcel(String footTitle, String[] headers,
			Collection<T> dataset, OutputStream out, HttpSession session) {
		export(footTitle, headers, dataset, out, "yyyy-MM-dd", session);
	}

	/**
	 * 导出excel
	 * 
	 * @param footTitle
	 *            脚标题
	 * @param headers
	 *            表头
	 * @param dataset
	 *            控制数据
	 * @param out
	 *            输出流
	 * @param pattern
	 *            验证
	 * @param session
	 *            会话
	 */
	public void exportExcel(String footTitle, String[] headers,
			Collection<T> dataset, OutputStream out, String pattern,
			HttpSession session) {
		export(footTitle, headers, dataset, out, pattern, session);
	}

	/**
	 * 通用的方法，利用了JAVA的反射机制，可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * 
	 * @param title
	 *            表格标题
	 * @param headers
	 *            表格属性列名数组
	 * @param dataset
	 *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
	 *            javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out
	 *            输出设备关联的流对象，可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern
	 *            如果有时间数据，设定输出格式。默认为"yyy-MM-dd"
	 * @param session
	 *            会话
	 */
	public void export(String title, String[] headers, Collection<T> dataset,
			OutputStream out, String pattern, HttpSession session) {
		// 申明一个工作簿
		XSSFWorkbook book = new XSSFWorkbook();
		// 创建一个表
		XSSFSheet sheet = book.createSheet();
		// 设置表格默认列宽度为25个字节
		sheet.setDefaultColumnWidth(25);
		// 声明一个画图的顶级管理器
		XSSFDrawing patriarch = sheet.createDrawingPatriarch();
		book.setSheetName(0, title); // 设置第一个sheet的名称
		XSSFRow row = sheet.createRow((short) 0);
		XSSFFont font = book.createFont();
		// font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
		font.setFontHeightInPoints((short) 9); // 设置字体大小
		font.setFontName("微软雅黑");
		XSSFCellStyle style = book.createCellStyle();
		style.setAlignment(XSSFCellStyle.ALIGN_CENTER); // 中对齐
		style.setFont(font);
		style.setBorderTop(XSSFCellStyle.BORDER_THIN);
		style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
		style.setBorderRight(XSSFCellStyle.BORDER_THIN);
		style.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		XSSFCellStyle style2 = book.createCellStyle();
		style2.setAlignment(XSSFCellStyle.ALIGN_CENTER); // 中对齐
		style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
		style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
		style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
		style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
		style2.setFont(font);
		for (short i = 0; i < headers.length; i++) {
			XSSFCell cell = row.createCell(i);
			cell.setCellStyle(style);
			XSSFRichTextString text = new XSSFRichTextString(headers[i]);
			cell.setCellValue(text);
		}
		// 循环数据
		Iterator<T> it = dataset.iterator();
		int index = 0;
		while (it.hasNext()) {
			index++;
			row = sheet.createRow(index);
			T t = (T) it.next();
			// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值
			Field[] fields = t.getClass().getDeclaredFields();

			for (int i = 0; i < fields.length; i++) {
				XSSFCell cell = row.createCell(i);
				cell.setCellStyle(style2);
				Field field = fields[i];
				String fieldName = field.getName();
				// 如果fieldName是idCard就进入if里面
				if (fieldName.equals("idCard")) {
					fieldName = fieldName.equals("idCard") ? "IDCard"
							: fieldName;
				}
				String getMethodName = "get"
						+ fieldName.substring(0, 1).toUpperCase()
						+ fieldName.substring(1);
				try {
					Class<? extends Object> tCls = t.getClass();
					Method getMethod = tCls.getMethod(getMethodName,
							new Class[] {});
					Object value = getMethod.invoke(t, new Object[] {});
					// 判断值的类型后进行强制类型转换
					String textValue = null;
					if (value instanceof Boolean) {
						boolean bValue = (Boolean) value;
						textValue = "男";
						if (!bValue) {
							textValue = "女";
						}
					} else if (value instanceof Date) {
						Date date = (Date) value;
						SimpleDateFormat sdf = new SimpleDateFormat(pattern);
						textValue = sdf.format(date);
					} else if (value instanceof Double) {
						double value1 = Double.parseDouble(value.toString());
						textValue = Arith.doubleTransform(value1);
					} else if (value instanceof byte[]) {
						// 有图片时，设置行高为60px;
						row.setHeightInPoints(60);
						// 设置图片所在列宽度为80px,注意这里单位的一个换算
						sheet.setColumnWidth(i, (short) (35.7 * 80));
						byte[] bsValue = (byte[]) value;
						XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0,
								1023, 255, (short) 6, index, (short) 6, index);
						anchor.setAnchorType(2);
						patriarch.createPicture(anchor, book.addPicture(
								bsValue, XSSFWorkbook.PICTURE_TYPE_JPEG));
					} else {
						// 判断value是否为空
						if (value != null) {
							// 其它数据类型都当作字符串简单处理
							textValue = value.toString();
						}
					}
					// 如果不是图片数据，就利用正则表达式判断textValue是否全部由数字组成
					if (textValue != null) {
						Pattern p = Pattern.compile("^//d+(//.//d+)?$");
						Matcher matcher = p.matcher(textValue);
						if (matcher.matches()) {
							// 是数字当作double处理
							cell.setCellValue(Double.parseDouble(textValue));
						} else {
							XSSFRichTextString richString = new XSSFRichTextString(
									textValue);
							richString.applyFont(font);
							cell.setCellValue(richString);
						}
					}
				} catch (SecurityException e) {

					e.printStackTrace();
				} catch (NoSuchMethodException e) {

					e.printStackTrace();
				} catch (IllegalArgumentException e) {

					e.printStackTrace();
				} catch (IllegalAccessException e) {

					e.printStackTrace();
				} catch (InvocationTargetException e) {

					e.printStackTrace();
				} finally {
					// 清理资源
				}
			}

		}
		try {
			book.write(out);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * 通用的方法，利用了JAVA的反射机制，可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * 可将指定对象中的属性对象中的一个字段导出
	 * 
	 * @param title
	 *            表格标题
	 * @param headers
	 *            表格属性列名数组
	 * @param dataset
	 *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
	 *            javabean属性的数据类型有基本数据类型及String,Date,
	 * @param out
	 *            输出设备关联的流对象，可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern
	 *            如果有时间数据，设定输出格式。默认为"yyy-MM-dd"
	 * @param session
	 *            会话
	 * 
	 * @param map
	 *           Map<String,String> map<K,V> k:指定对象属性名，V，对象中的值
	 * @param replaceMap  Map<String,Map<String,String>> map<k,map<k1,V>>
	 *                    k指定需要替换的属性，K1实际值，V替换值               
	 */
	public void exportExcel(String title, String[] headers,
                            Collection<T> dataset, OutputStream out, String pattern,
                            HttpSession session, Map<String, String> map, Map<String, Map<String, String>> replaceMap) {
		// 申明一个工作簿
		XSSFWorkbook book = new XSSFWorkbook();
		// 创建一个表
		XSSFSheet sheet = book.createSheet();
		// 设置表格默认列宽度为25个字节
		sheet.setDefaultColumnWidth(25);
		// 声明一个画图的顶级管理器
		XSSFDrawing patriarch = sheet.createDrawingPatriarch();
		book.setSheetName(0, title); // 设置第一个sheet的名称
		XSSFRow row = sheet.createRow((short) 0);
		XSSFFont font = book.createFont();
		// font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
		font.setFontHeightInPoints((short) 9); // 设置字体大小
		font.setFontName("微软雅黑");
		XSSFCellStyle style = book.createCellStyle();
		style.setAlignment(XSSFCellStyle.ALIGN_CENTER); // 中对齐
		style.setFont(font);
		style.setBorderTop(XSSFCellStyle.BORDER_THIN);
		style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
		style.setBorderRight(XSSFCellStyle.BORDER_THIN);
		style.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		XSSFCellStyle style2 = book.createCellStyle();
		style2.setAlignment(XSSFCellStyle.ALIGN_CENTER); // 中对齐
		style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
		style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
		style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
		style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
		style2.setFont(font);
		for (short i = 0; i < headers.length; i++) {
			XSSFCell cell = row.createCell(i);
			cell.setCellStyle(style);
			XSSFRichTextString text = new XSSFRichTextString(headers[i]);
			cell.setCellValue(text);
		}
		try {
			// 循环数据
			Iterator<T> it = dataset.iterator();
			int index = 0;
			while (it.hasNext()) {
				index++;
				row = sheet.createRow(index);
				T t = (T) it.next();
				// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值

				Field[] fields = t.getClass().getDeclaredFields();
				for (int i = 1; i < fields.length; i++) {
					String textValue = "";
					XSSFCell cell = row.createCell(i-1);
					cell.setCellStyle(style2);
					Field field = fields[i];
					String fieldName = field.getName();
					String getMethodName = "get"
							+ fieldName.substring(0, 1).toUpperCase()
							+ fieldName.substring(1);
					Class<? extends Object> tCls = t.getClass();
					Method getMethod = tCls.getMethod(getMethodName,
							new Class[] {});
					Object value = getMethod.invoke(t, new Object[] {});
					if (null != map && StringUtils.isNotEmpty(map.get(fieldName))) {
						if (null != value) {
							String fileName2 = map.get(fieldName);
							Class<? extends Object> tCls2 = value.getClass();
							String getMethodName2 = "get"
									+ fileName2.substring(0, 1).toUpperCase()
									+ fileName2.substring(1);
							Method getMethod2 = tCls2.getMethod(getMethodName2,
									new Class[] {});
							Object value2 = getMethod2.invoke(value,
									new Object[] {});
							if (value2 != null) {
								// 其它数据类型都当作字符串简单处理
								textValue = value2.toString();
							}
						}
						
					} else {
						if (value instanceof Date) {
							Date date = (Date) value;
							SimpleDateFormat sdf = new SimpleDateFormat(pattern);
							textValue = sdf.format(date);
						}else if(null!=replaceMap&&null!=replaceMap.get(fieldName)){
							Map<String, String> mapP=replaceMap.get(fieldName);
							textValue = mapP.get(value.toString());
							
						}else{
						// 判断value是否为空
						if (value != null) {
							// 其它数据类型都当作字符串简单处理
							textValue = value.toString();
						}
						}
					}
					if (textValue != null) {
						Pattern p = Pattern.compile("^//d+(//.//d+)?$");
						Matcher matcher = p.matcher(textValue);
						if (matcher.matches()) {
							// 是数字当作double处理
							cell.setCellValue(Double.parseDouble(textValue));
						} else {
							XSSFRichTextString richString = new XSSFRichTextString(
									textValue);
							richString.applyFont(font);
							cell.setCellValue(richString);
						}
					}
				}

			}

		} catch (Exception e) {
			 e.printStackTrace();
		}
		try {
			book.write(out);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
